<?php

class Model_User extends Joob_Db_Table	{
	
	protected $key = "id";
	
	protected $db = "users";
	
	## AUTHENTICATION FUNCTIONS
	
	public function login() {
		$email = $this->email;
		$password = $this->pwd;
		
		$errors = array();
		
		if (! Joob_Utils_Validator::email($email)) {
			$errors[] = "Email không hợp lệ.";
			return $errors; 
		}
		
		if (! Joob_Utils_Validator::password($password)) {
			$errors[] = "Password không hợp lệ.";
			return $errors;
		}
		
		$rows = $this->search("email='$email' " , 'id, pwd, activated', 1);
		
		if (count($rows) != 1 || $rows[0]->pwd!=sha1($password)) {
			$errors[] = "Email hoặc password không hợp lệ.";
			return $errors;
		} else {
			if($rows[0]->activated!=1)
			{
				$errors[] = "Tài khoản chưa được kích hoạt hoặc đã bị khóa.";
				return $errors;
			}
			else{
				$this->extend($rows [0]);
				return true;
			}
		}
	}
	
	public function register($auto_login = false) {
		SQL::commit();

		$errors = array();
		
		if (! Joob_Utils_Validator::email($this->email)) {
			throw new Exception("Email không hợp lệ.");
		}

		if (! $this->unique('email', $this->email)) {
			throw new Exception("Email đã được sử dụng.");
		}
		
		if (! $this->unique('alias', $this->alias)) {
			throw new Exception("Alias đã được sử dụng.");
		}

		if (! Joob_Utils_Validator::safeChar($this->fullname, 1, 100)) {
			throw new Exception("Tên không hợp lệ ({$this->first_name}).");
		}

		if (! Joob_Utils_Validator::password($this->pwd, 6, 32)) {
			throw new Exception("Mật khẩu không hợp lệ.");
		}
		$this->pwd = sha1($this->pwd);
		$this->since = time();
		$this->activated = 1;
		$this->role=1;

		if ($this->insert("fullname, email, pwd,
        	activated, since, role, alias") <= 0) {
			SQL::markError();
			$errors[] = "Connection database error";
        }
        SQL::finish();
        if (count($errors) > 0)	{
        	return $errors;
        }
        return true;
	}
	
	public function lostPassword(){
		$this->pwd=Joob_Utils_Word::random(13);
		$this->edit('pwd');
			
		$sender='bkprofile@bkprofile.com';
		$subject=' Tạo mật khẩu mới!';
		$content=' Mật khẩu mới: '.$this->pwd.'
					
						Ban quản trị <a href="http://bkprofile.com/">JOOB</a>';
		$headers=" MIME-Version: 1.0 \n\r";
		$headers.="Content-type:text/html;charset=UTF-8 \r\n";
		$headers.="From <".$sender.">\r\n";

		if(!mail($this->email, $subject, $content, $headers))
			throw new Exception("Tạo mật khẩu mới thất bại.");
		else
			return true;
	}
	
	
	## FRIENDS FUNCTIONS
	
	/**
	 * @desc Return array of friend ids .
	 */
	public function getFriendIds($page=0,$page_size=500){
		$friend = new Model_Friend();
		$rs =$friend->search('user_id1='.$this->id.' or user_id2='.$this->id.' and state=1','user_id1,user_id2', $page*$page_size.','.$page_size, 'id DESC');
		$ids = array();
		if(sizeof($rs)>0){
			for($i=0;$i<sizeof($rs);$i++){
				if($rs[$i]->user_id1 == $this->id)
					$ids[] = $rs[$i]->user_id2;
				else $ids[] = $rs[$i]->user_id1;
			}
		}
		return $ids;
	}
	
	public function getFriends($page='',$page_size='', $queryLocation = true){
		$friendship = new Model_Friendship();
		$friends = $friendship->getFriends($this->id, $page,$page_size);
		
		if (!$queryLocation)
			return $friends;
		
		$result = array();
		foreach($friends as $friend){
			$real_distance = Model_Map::getDistance($this->lat, $this->lng, $friend->lat, $friend->lng);
			$real_distance = explode('.',$real_distance);
			$distance = $real_distance[0];
			if($real_distance[1]) $distance .= ','.substr($real_distance[1],0,3);
			$listNeighbour = array('id'=>$friend->user_id, 
					'name'=>$friend->fullname,
					'gender'=>$friend->gender, 
					'lat'=>$friend->lat,
					'lng'=>$friend->lng,
					'distance'=>$distance
			);
			$result[] = $friend;
		}
		return $result;
	}
	
	/**
	 * @desc Return list of friend invitations (user_id1 invite user_id2).
	 */

	public function getInvitations($page,$page_size){
		$friend = new Model_Friend();
		return $friend->search('user_id2='.$this->id.' and state=0','*', $page*$page_size.','.$page_size, 'id DESC');
	}
	
	public function makeRequest($other_user,$message=""){
		$friend = new Model_Friend();
		$friend->setOption('user_id1',$this->id);
		$friend->setOption('user_id2',$other_user);
		$friend->setOption('state',0);
		$friend->setOption('msg',$message);
		
		$notification = new Model_Notification();
		$notification->setOption("user_id", $other_user);
		$notification->setOption("target_id", $this->id);
		$notification->setOption("type", "friendrequest");
		$notification->setOption("content",$this->fullname." muốn kết bạn với bạn");
		$notification->setOption("since",time());
		$notification->add();
		return $friend->addFriend();
	}
	
	public function refuseRequest($user_id){
		$req = new Model_Friend();
		$reqarr = $req->search(" user_id1='".$user_id."' and user_id2='".$this->id."'",'*',1);
		if(sizeof($reqarr)>0){
			$req->setOption('id',$reqarr[0]->id);
			if($req->connect()){
				$notification = new Model_Notification();
				$notification->setOption("user_id", $user_id);
				$notification->setOption("target_id", $this->id);
				$notification->setOption("type", "friendrefuse");
				$notification->setOption("content",$this->name." từ chối kết bạn với bạn");
				$notification->setOption("since",time());
				$notification->add();

				return $req->delete();
			}
			else{
				return false;
			}
		}
	}
	public function acceptRequest($user_id){
		$req = new Model_Friend();
		$reqarr = $req->search(" user_id1='".$user_id."' and user_id2='".$this->id."'",'*',1);
		if(sizeof($reqarr)>0){
			$req->setOption('id',$reqarr[0]->id);
			if($req->connect()){
				$other_user = new Model_User();
				$other_user->setOption('id',$user_id);
				if($other_user->connect()){
					$req->setOption('state',1);
					if($req->edit('state')){
						$notification = new Model_Notification();
						$notification->setOption("user_id", $user_id);
						$notification->setOption("target_id", $this->id);
						$notification->setOption("type", "friendaccept");
						$notification->setOption("content", $this->name." đồng ý kết bạn với bạn");
						$notification->add();
						return true;
					}
				}
				else throw new Exception('Tài khoản gửi lời mời không tồn tại hoặc đã bị khóa.');
			}
			else throw new Exception('Lời mời không tồn tại.');
		}
		return false;
	}
	public function removeFriend($user_id){
		$sql = 'DELETE FROM friends WHERE (user_id1='.$this->id.' and user_id2='.$user_id.') or (user_id2='.$user_id.' and user_id1='.$this->id.')';
		return SQL::update($sql);
	}
	
	/**
	 * @desc Check if other user is friend.
	 */

	public function isInviting($other_user){
		$friend = new Model_Friend();
		$friend->setOption('user_id',$this->id);
		$friend->setOption('friend_id',$other_user->id);
		return $friend->isInFriend();
	}
	
	## NOTIFICATIONS FUNCTIONS
	
	public function getNotification($page,$page_size){
		$notification = new Model_Notification();
		return $notification->search('user_id='.$this->id,'*', $page*$page_size.','.$page_size, 'id DESC');
	}
	
	
	## PLACE FUNCTIONS
	
	/**
	 * Function saveLocation($newLat, $newLng)
	 * ------------------------------------
	 * @desc	Save information about the location of the user.
	 *          Before sending request, we will verify that
	 *          the location has changed, or nothing is triggered.
	 * @return	true if success, else return false.
	 */

	public function saveLocation($newLat, $newLng,$isCheckin=0,$place_id=null,$place_name=null){
		if (($newLat == $this->lat) && ($newLng == $this->lng)){
			// nothing has changed
			return true;
		}elseif ($isCheckin==0){
			$this->setOption('lat', $newLat);
			$this->setOption('lng', $newLng);
			$this->setOption('is_checkin',0);
			$this->edit('lat, lng,is_checkin');
			$this->setNearestPlace(5);
			return true;
		}else{
			$this->setOption('lat', $newLat);
			$this->setOption('lng', $newLng);
			$this->setOption('place_id',$place_id);
			$this->setOption('place_name',$place_name);
			$this->setOption('is_checkin',1);
			return $this->edit('lat, lng,place_id,place_name');
		}
	}
	
	/**
	 * Function getFriendsNearby($dist, $limit)
	 * ------------------------------------
	 * @desc	Find all nearby friends within $dist.
	 *          If $dist=0, then we simply sort friends nearby
	 *          by distance, and return the closest lists.
	 * @param   $dist : value of distance in kilometers.
	 *          $limit indicates the max number of returned records.
	 * @return	Return an array of users
	 */

	public function getFriendsNearby($lat,$lng, $dist=5,$page,$page_size){
		if($lat==''){
			$lat = $this->lat;
		}
		if($lng==''){
			$lng = $this->lng;
		}
		// R = earth’s mean radius
		$R = 6371;
		// first-cut bounding box (in degrees)
		$maxLat = $lat + rad2deg($dist/$R);
		$minLat = $lat - rad2deg($dist/$R);
		// compensate for degrees longitude getting smaller with increasing latitude
		$maxLng = $lng + rad2deg($dist/$R/cos(deg2rad($lat)));
		$minLng = $lng - rad2deg($dist/$R/cos(deg2rad($lat)));
		 
		$friendship = new Model_Friendship();
		$listNeighbours = $friendship->getFriendsNearby($this->id,$maxLat,$minLat,$maxLng,$minLng, $page,$page_size);
		$result = array();
		foreach($listNeighbours as $listNeighbour){
//			var_dump($listNeighbour);die();
			$real_distance = Model_Map::getDistance($lat, $lng, $listNeighbour->lat, $listNeighbour->lng);
			$real_distance = explode('.',$real_distance);
			$distance = $real_distance[0];
			if($real_distance[1]) $distance .= ','.substr($real_distance[1],0,3);
			$listNeighbour = array('id'=>$listNeighbour->user_id, 
					'name'=>$listNeighbour->fullname,
					'gender'=>$listNeighbour->gender, 
					'lat'=>$listNeighbour->lat,
					'lng'=>$listNeighbour->lng,
					'distance'=>$distance
			);
			$result[] = $listNeighbour;
		}
		return $result;
	}
	
	
	/**
	 * Function getPeopleNearby($dist, $limit)
	 * ------------------------------------
	 * @desc	Find all people nearby within $dist
	 *          (Work the same as getFriendsNearby())
	 * @param	$dist : value of distance in kilometers.
	 * @return	$limit indicates the max number of returned records.
	 */

	public function getUsersNearby($lat,$lng, $dist=5,$page,$page_size){

		// R = earth’s mean radius
		$R = 6371;
		// first-cut bounding box (in degrees)
		$maxLat = $lat + rad2deg($dist/$R);
		$minLat = $lat - rad2deg($dist/$R);
		// compensate for degrees longitude getting smaller with increasing latitude
		$maxLng = $lng + rad2deg($dist/$R/cos(deg2rad($lat)));
		$minLng = $lng - rad2deg($dist/$R/cos(deg2rad($lat)));
		if($this->id > 0){
			$friendIds = $this->getFriendIds();
			$in = $this->id;
			if(sizeof($friendIds)>0){
				for($i=0;$i<sizeof($friendIds);$i++){
					$in.=','.$friendIds[$i];
				}
			}
			$notFriends = ' and id not in ('.$in.') ';
		}
		$condition = "activated=1 ".$notFriends." and (lat < {$maxLat}) and (lat > {$minLat})
            and (lng < {$maxLng}) and (lng > {$minLng})";
		$listNeighbours = $this->search($condition, "id,fullname,gender,lat,lng", $page*$page_size.','.$page_size);
		$result = array();
//		var_dump($listNeighbours);die();
		foreach($listNeighbours as $listNeighbour){
//			var_dump($listNeighbour);die();
			$real_distance = Model_Map::getDistance($lat, $lng, $listNeighbour->lat, $listNeighbour->lng);
			$real_distance = explode('.',$real_distance);
			$distance = $real_distance[0];
			if($real_distance[1]) $distance .= ','.substr($real_distance[1],0,3);
			$listNeighbour = array('id'=>$listNeighbour->id, 
					'name'=>$listNeighbour->fullname,
					'gender'=>$listNeighbour->gender, 
					'lat'=>$listNeighbour->lat,
					'lng'=>$listNeighbour->lng,
					'distance'=>$distance
			);
			$result[] = $listNeighbour;
		}
		return $result;
	}
	
	public function getNearbyPlace($group_id,$lat,$lng,$dist,$page,$page_size){
		$place = new Model_Place();
		 
		// R = earth’s mean radius
		$R = 6371;
		// first-cut bounding box (in degrees)
		$maxLat = $lat + rad2deg($dist/$R);
		$minLat = $lat - rad2deg($dist/$R);
		// compensate for degrees longitude getting smaller with increasing latitude
		$maxLng = $lng + rad2deg($dist/$R/cos(deg2rad($lat)));
		$minLng = $lng - rad2deg($dist/$R/cos(deg2rad($lat)));
		 
		$subgroups = Model_PlaceGroup::getSubById($group_id);
		$in = $group_id;
		if(sizeof($subgroups)>0){
			for($i=0;$i<sizeof($subgroups);$i++){
				$in.=','.$subgroups[$i]->id;
			}
		}
		$condition = 'activated=1 and (lat < '.$maxLat.') and (lat > '.$minLat.') and (lng < '.$maxLng.') and (lng > '.$minLng.')';
		if($group_id>0){
			$condition.= ' and group_id in ('.$in.')';
		}
		
		$places = $place->search($condition, "id,name,address,lat,lng,rank", $page*$page_size.','.$page_size);
		$result = array();
		foreach($places as $place){
			$real_distance = Model_Map::getDistance($lat, $lng, $place->lat, $place->lng);
			$real_distance = explode('.',$real_distance);
			$distance = $real_distance[0];
			if($real_distance[1]) $distance .= ','.substr($real_distance[1],0,3);
			$place = array('id'=>$place->id, 
					'name'=>$place->name, 
					'address'=>$place->address, 
					'lat'=>$place->lat,
					'lng'=>$place->lng,
					'distance'=>$distance,
					'rank'=>$place->rank
			);
			$result[] = $place;
		}
		return $result;
	}
	
	public function editInfo()	{
		return $this->edit('fullname, gender, hobbies, dob_day, dob_month, dob_year');
	}
	
	public function getInfo()	{
		$user = $this;
		return array('id'=>$user->id,
					'email'=>$user->email, 
					'fullname'=>$user->fullname, 
					'gender'=>$user->gender, 
					'avatar'=>$user->avatar, 
					'hobbies'=>$user->hobbies,
					'relationship'=>$user->relationship,
					'dob_day'=>$user->dob_day,
					'dob_month'=>$user->dob_month,
					'dob_year'=>$user->dob_year,
					'place_id'=>$user->place_id,
					'place_name'=>$user->place_name
		);
	}
	
	public function updateNotificationTime()	{
		$this->last_notification_time = time();
		return $this->edit('last_notification_time');
	}
	
	public function setNearestPlace($dist){
		$place = new Model_Place();
		 
		// R = earth’s mean radius
		$R = 6371;
		for($i=1;$i<=$dist;$i++){
			// first-cut bounding box (in degrees)
			$maxLat = $this->lat + rad2deg($i/$R);
			$minLat = $this->lat - rad2deg($i/$R);
			// compensate for degrees longitude getting smaller with increasing latitude
			$maxLng = $this->lng + rad2deg($i/$R/cos(deg2rad($this->lat)));
			$minLng = $this->lng - rad2deg($i/$R/cos(deg2rad($this->lat)));
			 
			$condition = 'activated=1 and (lat < '.$maxLat.') and (lat > '.$minLat.') and (lng < '.$maxLng.') and (lng > '.$minLng.')';

			$nearestplace = $place->search($condition, "id,`name`", 1);
			if(sizeof($nearestplace)>0){
				$this->setOption('place_id', $nearestplace[0]->id);
				$this->setOption('place_name', 'gần '.$nearestplace[0]->name);
				$this->edit('place_id, place_name');
				break;
			}
		}
	}

	public function checkin($place_id){
		$place = new Model_Place();
		$place->id = $place_id;
		if($place->connect()){
			$checkin = new Model_Checkin();
			$checkin->user_id = $this->id;
			$checkin->place_id = $place_id;
			$checkin->user_name = $this->fullname;
			$checkin->place_name = $place->name;
			$checkin->public_id = 2;
			$check = $checkin->checkCheckedIn();
			if($check){
				return false;
			}
			$check = $checkin->checkin();
			$check = $this->saveLocation($place->lat, $place->lng,1,$place->id,$place->name);
			$feed = new Model_Feed();
			$feed->content = ' đang ở <a href="#page/Place/id/'.$place_id.'">'.$place->name.'</a>';
			$feed->from_id = $this->id;
			$feed->checkinFeed();
			return $check;
		}
		else{
			return false;
		}
	}
	
	public function checkout($place_id){
		$place = new Model_Place();
		$place->id = $place_id;
		if($place->connect()){
			$checkin = new Model_Checkin();
			$checkin->user_id = $this->id;
			$checkin->place_id = $place_id;
			$checkin_rs = $checkin->search('user_id = '.$this->id.' and place_id='.$place_id.' and time_out is null','id');
			if(count($checkin_rs)>0){
				$checkin->id = $checkin_rs[0]->id;
				$checkin->connect();
				$check = $checkin->checkCheckedIn();
				if(!$check){
					return false;
				}
				$check = $checkin->checkout();
				$feed = new Model_Feed();
				$feed->content = ' vừa rời khỏi <a href="#page/Place/id/'.$place_id.'">'.$place->name.'</a>';
				$feed->from_id = $this->id;
				$feed->checkinFeed();
				$this->is_checkin = 0;
				$this->edit('is_checkin');
	// 				$check = $this->saveLocation($place->lat, $place->lng,1,$place->name);*/
				return $check;
			}
			else return false;
		}
		else{
			return false;
		}
	}
}

?>